<?php

declare(strict_types=1);

namespace App\Job;
use App\Model\Applet;
use App\Model\AppletPlayletRel;
use App\Model\DataPaymentCheckLog;
use App\Model\DataPaymentRefund;
use App\Model\DataPaymentRefundLog;
use App\Model\Playlet;
use App\Model\PlayletEpisodes;
use GuzzleHttp\Client;
use Hyperf\AsyncQueue\Job;
use Hyperf\DbConnection\Db;
use Psr\Log\LoggerInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Logger\LoggerFactory;
class WxRefundOrderJob extends Job
{

    public $ids;

    public $redis;
    protected LoggerInterface $logger;

    public static $getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";

    public function __construct($refund_id,$paymentInfo,$handle_User_id,$refund_reason)
    {
        $container = ApplicationContext::getContainer();
        $this->logger = $container->get(LoggerFactory::class)->get('log', 'wxRefundOrder');
        $this->refund_id = $refund_id;
        $this->paymentInfo = $paymentInfo;
        $this->handle_user_id = $handle_User_id;
        $this->refund_reason = $refund_reason;
    }

    public function handle()
    {
        $refund_id = $this->refund_id;
        $paymentInfo = $this->paymentInfo;
        $handle_User_id = $this->handle_user_id;
        $refund_reason = $this->refund_reason;
        $req_from = 1;
        try {
            $this->logger->info('开始提交订单退款逻辑');
            //查询小程序的key
            $appletInfo = Applet::query()->where('id',$paymentInfo->applet_id)->select(['id','AppKey','app_id','app_secret'])->first();
//            $accessToken = env('WX_TEST_TOKEN');
            $accessToken = $this->getWxAccessToken($appletInfo->id,$appletInfo->app_id,$appletInfo->app_secret);
            if(!empty($accessToken)){
                $userInfo = Db::table('data_user_'.$paymentInfo->applet_id)->where('id',$paymentInfo->user_id)->first();
                $orderResult = $this->checkWxOrder($handle_User_id,$paymentInfo->id,$userInfo->xc_open_id, $paymentInfo->order_id,$appletInfo->AppKey,$accessToken,2);
                if($orderResult['errcode'] == 0){
                    $orderInfo = $orderResult['order'];
//
                    $refund_order_id = $this->getReturnOrderId($paymentInfo->applet_id,$paymentInfo->user_id,$paymentInfo->goods_id);
//
                    $returnOrderResult = $this->refundWxOrder($handle_User_id,$paymentInfo->id,$userInfo->xc_open_id,$paymentInfo->order_id,$refund_order_id,
                        $appletInfo->AppKey,$accessToken,$refund_reason,$req_from,$paymentInfo->amount,$orderInfo['left_fee']);
//
                    if($returnOrderResult['errcode'] == 0){
                        $this->UpdateRefundData($handle_User_id,$refund_id,$returnOrderResult,2);
                    }else{
                        $this->UpdateRefundData($handle_User_id,$refund_id,$returnOrderResult,4);
                    }
                }else{
                    $this->logger->error('查询线上微信订单错误',[]);
                    $this->UpdateRefundData($handle_User_id,$refund_id,array(),4,'查询线上微信订单错误');
                }
            }else{
                $this->logger->error('微信token问题',[$accessToken]);
                $this->UpdateRefundData($handle_User_id,$refund_id,array(),4,'微信token问题');
            }
        }catch (\Exception $e){
            $this->logger->error('请求微信退款订单|错误：' . $e->getLine() . '|' . $e->getMessage());
            $this->UpdateRefundData($handle_User_id,$refund_id,array(),4,'请求微信退款订单|错误'.$e->getMessage());
        }
    }

    public function UpdateRefundData($handle_User_id,$refund_id,$orderInfo,$status=1,$refund_order_msg = ''){


        $refund_order_id = $orderInfo['refund_order_id'] ?? 0;
        $refund_wx_order_id = $orderInfo['refund_wx_order_id'] ?? 0;
        $pay_order_id = $orderInfo['pay_order_id'] ?? 0;
        $pay_wx_order_id = $orderInfo['pay_wx_order_id'] ?? 0;


        DataPaymentRefund::query()->where(['id' => $refund_id])->update([
            'handle_User_id' => $handle_User_id,
            'refund_order_id' => $refund_order_id,
            'status' => $status,
            'refund_wx_order_id' => $refund_wx_order_id,
            'pay_order_id' => $pay_order_id,
            'pay_wx_order_id' => $pay_wx_order_id,
            'refund_order_msg' => $refund_order_msg
        ]);
    }

    /**
     * 检查微信订单
     */
    public function checkWxOrder($click_user_id,$payment_id,$xc_open_id,$order_id,$appkey,$accessToken,$type,$pay_type=1){

        if($pay_type == 1){

            $url = '/xpay/query_order';
            $params = [
                'openid' => $xc_open_id,
                'env'=>0,
                'order_id' => $order_id
            ];
            $pay_sig = $this->get_paySig($appkey,$url,$params);
            $orderUrl = 'https://api.weixin.qq.com'.$url.'?access_token='.$accessToken.'&pay_sig='.$pay_sig;
            $orderResult  = $this->request($params,$orderUrl, 'POST');
            if($orderResult['errcode'] == 0){
                $return_msg = '获取成功';
            }else{
                $return_msg = $orderResult['errmsg'];
            }
            //插入日志
            $this->installCreateLog($click_user_id,$payment_id,$return_msg,$orderResult,$orderUrl,$params,$type);
            return $orderResult;
        }

    }

    /**
     * 插入查看日志
     */
    public function installCreateLog($user_id,$payment_id,$return_msg,$reutrnData,$request_url,$request_params,$type){

        $return_text = json_encode($reutrnData);
        $request_params = json_encode($request_params);
        DataPaymentCheckLog::Create([
            'user_id' => $user_id,
            'payment_id' => $payment_id,
            'return_msg' => $return_msg,
            'return_text' => $return_text,
            'request_url' => $request_url,
            'request_params' => $request_params,
            'type' => $type,
        ]);
    }

    /**
     * 退款微信订单
     */
    public function refundWxOrder($click_user_id,$payment_id,$xc_open_id,$order_id,$refund_order_id,$appkey,$accessToken,$refund_reason,$req_from,$amount,$left_fee){


        $url = '/xpay/refund_order';
        $params = [
            'openid' => $xc_open_id,
            'order_id' => $order_id,
            'refund_order_id' => $refund_order_id,
            'left_fee'   => $left_fee,
            'refund_fee' => $amount,
            'biz_meta' => 'refund_order',
            'env'=> 0,
            'refund_reason' => $refund_reason,
            'req_from' => $req_from
        ];
        $pay_sig = $this->get_paySig($appkey,$url,$params);
        $orderUrl = 'https://api.weixin.qq.com'.$url.'?access_token='.$accessToken.'&pay_sig='.$pay_sig;
        $this->logger->info('请求退款数据：'.PHP_EOL.var_export(['result' => $params], true));
        $this->logger->info('请求退款Url：'.$orderUrl);
        $refundResult  = $this->request($params,$orderUrl, 'POST');
        if($refundResult['errcode'] == 0){
            $this->logger->info('调用退款接口成功 返回数据：'.PHP_EOL.var_export(['result' => $refundResult], true));
            $this->installRefundLog($click_user_id,$payment_id,'获取成功',$refundResult,$orderUrl,$params);
            return $refundResult;
        }else{
            $this->logger->error('调用退款接口失败 返回数据：'.PHP_EOL.var_export(['result' => $refundResult], true));
            return $refundResult;
        }
    }

    /**
     * 插入退款日志
     */
    public function installRefundLog($user_id,$payment_id,$return_msg,$reutrnData,$request_url,$request_params){

        $return_text = json_encode($reutrnData);
        $request_params = json_encode($request_params);
        DataPaymentRefundLog::Create([
            'user_id' => $user_id,
            'payment_id' => $payment_id,
            'return_msg' => $return_msg,
            'return_text' => $return_text,
            'request_url' => $request_url,
            'request_params' => $request_params,
        ]);
    }
    /**
     * 获取退款订单ID
     */
    public function getReturnOrderId($applet_id,$user_id,$goods_id){
        $order_id = 'R'.time().mt_rand(10000,99999).$applet_id.$user_id.$goods_id;
        return $order_id;
    }

    public function getWxAccessToken($applet_id,$app_id,$app_secret){

        $container = ApplicationContext::getContainer();

        $redis = $container->get(\Hyperf\Redis\RedisFactory::class)->get('wx');

        $key = 'wx_access_token';
        $key .= $applet_id;
        $accessToken = $redis->get($key);
        if(empty($accessToken)){
            $params         = [
                'grant_type' => 'client_credential',
                'appid'    => $app_id,
                'secret'   => $app_secret
            ];
            //获取token
            $accessTokenInfo     = $this->request($params, self::$getTokenUrl,'GET');

            if (!empty($accessTokenInfo['access_token'])){
                $accessToken = $accessTokenInfo['access_token'];
                $redis->setex($key,7100,$accessToken);
            }else{
                $accessToken = "";
            }
        }
        return $accessToken;
    }

    /**
     * 生成虚拟支付的pay_sig
     */
    public function get_paySig($appkey,$url,$signData) {
        $paySig = $this->calcPaySig($url, $signData, $appkey);
        return $paySig;
    }
    /**
     * 生成虚拟支付的pay_sig
     */
    private function calcPaySig($uri, $postBody, $appkey)
    {
        $needSignMsg = $uri . '&' . json_encode($postBody);
        $paySig = hash_hmac('sha256', $needSignMsg, $appkey);
        return $paySig;
    }
    /**
     * 传入数组进行HTTP POST请求
     */
    function request(array $params, string $url,string $method)
    {
        $client   = new Client([
            'timeout' => 30
        ]);
        $headers       =['Content-Type' => 'application/json;charset=utf-8', 'Accept' => 'application/json','Accept-Charset' => 'utf-8'];
        $requestParams = [
            'headers' => $headers,
        ];
        if ($method == 'GET') {
            $requestParams['query'] = $params;
        } else {
            $requestParams['body'] = json_encode($params,JSON_UNESCAPED_UNICODE);
        }
//        var_dump($requestParams);
        $response = $client->request($method,$url, $requestParams);
        if ($response->getStatusCode() !== 200) {
            return '';
        }
        $result   = $response->getBody()->getContents();
        $resultArr = json_decode($result,true);
        return $resultArr;

    }
}